import { EventHandler, IEvent } from './Interface';

import { BaseEventEmitter, Observer } from './Observer';

/**
 * 事件消息管理，支持由创作者自定义事件。
 *
 * EventEmitter 是一个管理事件类，用于在应用中管理事件的触发和监听。
 * 它允许通过 `on`、`once`、`off` 等方法注册或移除事件监听器，并支持事件的触发和通知。
 *
 * 示例用法：
 * ```typescript
 * // 创建一个事件发射器实例
 * const emitter = new EventEmitter();
 *
 * // 注册事件监听器，当收到say事件时，打印事件文本
 * emitter.on('say', (text) => {
 *   console.log(text);
 * });
 *
 * // 触发say事件，并传入事件文本
 * emitter.emit('say', 'Hello, world!');
 * ```
 */
export class EventEmitter extends BaseEventEmitter<string> {
  on(eventName: string | '*', callback: EventHandler, target?: any): this;
  /**
   * 添加一个事件监听器。
   * 支持通配符 * 监听所有事件。
   *
   * @param eventName 事件名称。
   * @param callback 事件被触发时调用的回调函数。
   * @param target 可选参数，回调函数绑定的目标对象。
   * @returns 返回 EventEmitter 实例，支持链式调用。
   */
  on(eventName: string | '*', callback: EventHandler, target?: any): this {
    return this.addListener(eventName, new Observer(callback, target || this));
  }

  /**
   * 添加一个一次性事件监听器，事件触发后自动移除。
   * 支持通配符 * 监听所有事件。
   *
   * @param eventName 事件名称。
   * @param callback 事件被触发时调用的回调函数。
   * @param target 可选参数，回调函数绑定的目标对象。
   * @returns 返回 EventEmitter 实例，支持链式调用。
   */
  once(eventName: string | '*', callback: EventHandler, target?: any): this {
    return this.addListener(
      eventName,
      new Observer(callback, target || this, true)
    );
  }

  /**
   * 移除事件监听器。
   *
   * @param eventName 事件名称。
   * @param callback 可选参数，要移除的回调函数。
   * @param target 可选参数，要移除的回调函数绑定的目标对象。
   * @returns 返回 EventEmitter 实例，支持链式调用。
   */
  off(eventName: string | '*', callback?: EventHandler, target?: any): this {
    const observers = this.listeners.get(eventName);
    if (!observers) {
      return this;
    }

    if (!callback && !target) {
      this.removeAllListeners(eventName);
      return this;
    }

    observers.forEach((observer) => {
      if (
        (target && !callback && observer.compar(target)) ||
        (callback && !target && observer.callback === callback) ||
        (callback &&
          target &&
          observer.callback === callback &&
          observer.compar(target))
      ) {
        this.removeListener(eventName, observer);
      }
    });

    return this;
  }

  /**
   * 触发指定事件，所有监听该事件的监听器都会被通知。
   *
   * @param eventName 事件名称。
   * @param args 可选参数，传递给事件监听器的参数。
   * @returns 返回 EventEmitter 实例，支持链式调用。
   */
  private eventQueue: Array<{ eventName: string; args: any[] }> = [];
  private isProcessingQueue = false;
  private static readonly BATCH_SIZE = 10;

  emit(eventName: string, ...args: any[]): this {
    this.eventQueue.push({ eventName, args });

    if (!this.isProcessingQueue) {
      this.processEventQueue();
    }
    return this;
  }

  private processEventQueue(): void {
    this.isProcessingQueue = true;
    const batchSize = EventEmitter.BATCH_SIZE;

    while (this.eventQueue.length > 0) {
      const batch = this.eventQueue.splice(0, batchSize);
      batch.forEach(({ eventName, args }) => {
        this.notifyListeners(eventName, args);
        if (eventName !== '*') {
          this.notifyListeners('*', args);
        }
      });

      if (this.eventQueue.length > 0) {
        setTimeout(() => this.processEventQueue(), 0);
        break;
      }
    }

    this.isProcessingQueue = false;
  }

  /**
   * 派发一个事件对象，所有监听该事件类型的监听器都会被通知。
   *
   * @param event 事件对象，必须包含 type 属性。
   * @returns 返回 EventEmitter 实例，支持链式调用。
   */
  dispatchEvent(event: IEvent): this {
    if (!event?.type) {
      console.warn('事件对象必须包含 type 属性');
      return this;
    }

    if (event.target === undefined) {
      event.target = this;
    }

    this.notifyListeners(event.type, event);
    this.notifyListeners('*', event);
    return this;
  }

  /**
   * 检查是否有指定事件的监听器。
   *
   * @param eventName 事件名称。
   * @returns 如果存在指定事件的监听器则返回 true，否则返回 false。
   */
  hasEventListener(eventName: string): boolean {
    const observers = this.listeners.get(eventName);
    return !!observers?.size;
  }

  /**
   * 移除指定目标对象在所有事件中注册的所有监听器。
   *
   * @param target 要移除监听器的目标对象。
   * @returns 返回 EventEmitter 实例，支持链式调用。
   */
  targetOff(target: any): this {
    if (!target) {
      return this;
    }

    this.listeners.forEach((observers, eventName) => {
      observers.forEach((observer) => {
        if (observer.compar(target)) {
          this.removeListener(eventName, observer);
        }
      });
    });

    return this;
  }

  /**
   * 移除所有事件的所有监听器。
   *
   * @returns 返回 EventEmitter 实例，支持链式调用。
   */
  removeAll(): this {
    this.removeAllListeners();
    return this;
  }
}

/**
 * 全局事件总线实例化，支持由创作者自定义事件。
 *
 * Emitter 是一个全局管理事件实例，用于在整个应用中统一管理事件的触发和监听。
 * 它允许通过 `on`、`once`、`off` 等方法注册或移除事件监听器，并支持事件的触发和通知。
 *
 * 示例用法：
 * ```typescript
 * // 注册事件监听器，当收到say事件时，打印事件文本
 * Emitter.on('say', (text) => {
 *   console.log(text);
 * });
 *
 * // 触发say事件，并传入事件文本
 * Emitter.emit('say', 'Hello, world!');
 * ```
 */
export const Emitter = new EventEmitter();
